home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / ffuncs.arc / BLDFUNCS.C next >
Encoding:
C/C++ Source or Header  |  1988-09-02  |  13.7 KB  |  419 lines

  1. /* BLDFUNCS.C - Construct a table of the functions defined in src files.
  2.  * Copyright (c) 1988 Marvin Hymowech
  3.  *
  4.  * Usage:   bldfuncs file1.c file2.c ...
  5.  *          Wildcards are allowed also, e.g. *.c
  6.  *          The output table is named FUNCS.TXT
  7.  * 
  8.  * The typist changed all function names beginning with filter_...() to
  9.  * flt_...(). Example:  filter_data() changed to flt_data(). These were
  10.  * changed because the Mix Power C debugger only recognizes the first 8
  11.  * characters. Hence, it will report an internal CTRACE error (can't lo-
  12.  * cate symbol) with names like filter_ppdir() and filter_parens().
  13.  *    See the .DOC file in this .ARC file for information on setting up
  14.  * the environment variable GETFEDIT and for getting this program to acc-
  15.  * ept wildcards. Microsoft C has a library file that can be linked with
  16.  * BLDFUNCS enabling wildcard input but as far as I know, Quick C and
  17.  * Power C do not have this library file. It's called setargv. The
  18.  * BLDFUNCS.EXE & GETF.EXE files were made with Quick C and I also suc-
  19.  * cessfully compiled, linked, and ran them with Power C but with no wild-
  20.  * card input accepted with either.
  21.  *    Also, see the .DOC file to see how BLDFUNCS and GETF interact.
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include <ctype.h>
  26. #include <string.h>
  27. #define LINT_ARGS
  28.  
  29. #define TRUE  1
  30. #define FALSE 0
  31. #define OK    0
  32. #define ERROR 1
  33.  
  34. /* * return values for filter functions below.
  35.    * EOF or any character is also possible.
  36. */
  37.  
  38. #define BRACES -2
  39. #define PARENS -3
  40. #define QUOTES -4
  41.  
  42. /* function declarations for type checking */
  43. char *get_fn_name(char *);
  44. int get_names_one_file(char *, FILE *);
  45.  
  46. main(argc, argv)
  47. int argc;
  48. char **argv;
  49. {
  50.  
  51.    FILE *fp_out;
  52.    char *current_file;
  53.    int num_files, i;
  54.  
  55.    if (argc < 2) {
  56.       fprintf( stderr, "\nWrong number of parameters");
  57.       exit(1);
  58.    }
  59.  
  60.    if ( (fp_out = fopen("FUNCS.TXT", "w")) == NULL ) {
  61.       fprintf( stderr, "Can't open %s\n", "FUNCS.TXT");
  62.       exit(1);
  63.    }
  64.  
  65.    /* build a function list for each file on the command line
  66.       * and write the list to the file "FUNCS.TXT".
  67.    */
  68.  
  69.    /* tell the user where we're at */  /* this line (<---) is below in book*/
  70.    printf("Creating FUNCS.TXT...\n");
  71.    num_files = argc - 1;
  72.    for (i = 1; i <= num_files; i++) {
  73.       /* use strlwr to lower-case name - cosmetic only */
  74.       printf(" %30s: %3d of %3d files\n",
  75.                current_file = strlwr (*++argv), i, num_files );
  76.       if (get_names_one_file (current_file, fp_out ) != OK ) {
  77.          fprintf( stderr, "\nCan't process %s", current_file);
  78.          exit(1);
  79.       }
  80.    }
  81.  
  82.    fclose(fp_out);
  83.    exit(0);
  84. }
  85.  
  86.    /* open the c file source_file_name, scan it for function definitions,
  87.    *  and write a listing to fp_out in the form:
  88.    *        source_file_name:
  89.    *           function-1
  90.    *           function-2 ...
  91.    *           function-n;
  92.    *  Return values:  OK or ERROR
  93.    */
  94.  
  95. int get_names_one_file(source_file_name, fp_out)
  96. char *source_file_name;
  97. FILE *fp_out;
  98. {
  99.  
  100.    int line_len, c, got_fn_defn = FALSE;
  101.    #define LINE_LEN 8192
  102.    char line[LINE_LEN], *name_ptr, fn_name[64];
  103.    FILE *fp_source;
  104.  
  105.                               /* open the input source file */
  106.    if ( (fp_source = fopen(source_file_name, "r")) == NULL)
  107.       return ERROR;
  108.                               /* write "source file name:" */
  109.    sprintf( line, "\n%s:", source_file_name);
  110.    fprintf( fp_out, line);
  111.  
  112.    while( TRUE) {
  113.       line_len = 0;        /* using the flt_data() char stream */
  114.                            /* collect chars till a semicolon or PARENS */
  115.       while( (c = flt_data(fp_source)) != EOF && c != ';' && c != PARENS)
  116.          line[line_len++] = c;
  117.       if (c == EOF)
  118.          break;
  119.       if (c == ';')        /* Bypass externals representing data items */
  120.          continue;         /* Now we know line entered with PARENS */
  121.       line[line_len] = 0;  /* Truncate line */
  122.  
  123.             /* At this point, line either contains a function definition
  124.             *  or a function type declaration or something else, perhaps
  125.             *  an occurrence of parinthese in a data item definition.
  126.             *  We only want function definitions.
  127.             */
  128.                   /* Extract the function name from this possible */
  129.                   /* function definition, and save it in fn_name */
  130.       strcpy(fn_name, get_fn_name(line) );
  131.                   /* Exclude the case of parenthetical expressions in */
  132.                   /* a data definition, e.g. within srray brackets */
  133.       if ( !fn_name[0])
  134.          continue;
  135.                         /* skip white space */
  136.       while ( (c = flt_data(fp_source)) != EOF && isspace(c) )
  137.          ;
  138.       if (c == ';' || c == ',')     /* functs type check declaration */
  139.          continue;                  /* so bypass it */
  140.       if (c == EOF)
  141.          break;
  142.                         /* skip any parameter declarations - */
  143.       while (c != BRACES && c != EOF)  /* eat until braces or EOF */
  144.          c = flt_data(fp_source);
  145.  
  146.             /* append this function definition to the output table */
  147.       fprintf( fp_out, "\n\t%s", fn_name);
  148.       got_fn_defn = TRUE;
  149.    }     /* end while */
  150.    fclose(fp_source);
  151.                   /* got_fn_defn FALSE if no functions in file */
  152.                   /* write file terminator */
  153.    fputs( got_fn_defn ? ";\n" : "\n\t;\n", fp_out);
  154.    return OK;
  155. }  /* end get_names_one_file() */
  156.  
  157. /* assuming that the input line ends with a function name,
  158. *  extract and return this name (as a pointer into the input line)/
  159. */
  160. char *get_fn_name(line)
  161. char *line;
  162. {
  163.  
  164.    char *name_ptr;
  165.    int len;
  166.  
  167.    if ( !(len = strlen(line)) )
  168.       return line;
  169.    name_ptr = line + len - 1;
  170.    while (isspace(*name_ptr))       /* skip trailing white space */
  171.       name_ptr--;
  172.    *(name_ptr + 1) = 0;             /* terminate fn name */
  173.  
  174.                               /* function names consist entirely of alpha- */
  175.                               /* numeric chars and underscores */
  176.    while ( (isalnum(*name_ptr) || *name_ptr == '_') && name_ptr >= line)
  177.       name_ptr--;
  178.                               /* if this alleged function name begins */
  179.    if ( isdigit(*++name_ptr)) /* with a digit, return an empty string */
  180.       return( name_ptr + strlen(name_ptr) );
  181.    return name_ptr;           /* else return the function name */
  182. }     /* end get_fn_name */
  183.  
  184. /* Using the stream returned by flt_parens() as input, 
  185. *  return a character stream in which any data initialization
  186. *  exptessions between an equals sign and a simicolon
  187. *  have been replaced by a single semicolon.
  188. *  This will filter out anything involving parentheses in a
  189. *  data initialization expression, which might otherwise be
  190. *  mistaken for a function definition.
  191. */
  192.  
  193. int flt_data(fp_source)
  194. FILE *fp_source;
  195. {
  196.  
  197.    int c;
  198.  
  199.    if ( (c = flt_parens(fp_source)) != '=')
  200.       return c;
  201.    while ( (c = flt_parens(fp_source)) != ';' && c != EOF)
  202.       ;
  203.    return c;
  204. }     /* end flt_data() */
  205.  
  206. /* Using the stream returned by flt_curly_braces() as input,
  207.  * reutrn a character stream in which all characters between
  208.  * '{' and the matching '}' have been replaced by the
  209.  * single special value PARENS (any nested parentheses within
  210.  * this top level pair will also have been eaten).
  211.  * This will filter out anything within the parentheses delimiting
  212.  * the arguments in a function definition.
  213.  */
  214.  
  215. int flt_parens(fp_source)
  216. FILE *fp_source;
  217. {
  218.  
  219.    int paren_cnt, c;
  220.  
  221.    if ( (c = flt_curly_braces(fp_source)) != '(' )
  222.       return c;
  223.    paren_cnt = 1;
  224.    while (paren_cnt)
  225.       switch (flt_curly_braces(fp_source)) {
  226.          case ')':
  227.             paren_cnt--;
  228.             break;
  229.          case '(':
  230.             paren_cnt++;
  231.             break;
  232.          case EOF:
  233.             return EOF;
  234.       }
  235.    return PARENS;
  236. }
  237.  
  238. /* Using the stream returned by flt_ppdir() as input,
  239.  * return a character stream in which all characters between
  240.  * '{' and the matching '}' have been replaced by the
  241.  * single special value BRACES (any nested braces within
  242.  * this top level pair will also have been eaten). This
  243.  * will filter out anything internal to a function.
  244.  */
  245.  
  246. int flt_curly_braces(fp_source)
  247. FILE *fp_source;
  248. {
  249.  
  250.    int brace_cnt,c;
  251.  
  252.    if( (c = flt_ppdir(fp_source) ) != '{')
  253.       return c;
  254.    brace_cnt = 1;
  255.    while (brace_cnt)       /* wait for brace count to return to zero */
  256.       switch (flt_ppdir(fp_source)) {
  257.          case '}':
  258.             brace_cnt--;
  259.             break;
  260.          case '{':
  261.             brace_cnt++;
  262.             break;
  263.          case EOF:
  264.             return EOF;
  265.       }
  266.    return BRACES;          /* brace count is now zero */
  267. }
  268.  
  269. #define MAXLINE 1024
  270.  
  271. /* Using the stream returned by flt_quotes() as input,
  272.  * return a character stream in which all preprocessor
  273.  * directives have been eaten.
  274.  */
  275.  
  276. int flt_ppdir(fp_source)
  277. FILE *fp_source;
  278. {
  279.  
  280.    int c, i;
  281.    char line [MAXLINE + 1];
  282.  
  283.    while (TRUE) {    /* Does this line begin a preprocessor directive? */
  284.       if ( (c = flt_quotes(fp_source)) != '#')
  285.          return c;      /* no, return character */
  286.                         /* yes, store until newline or EOF */
  287.       if ( (c = get_ppdir_line(fp_source, line)) == EOF)
  288.          return EOF;
  289.       if (strncmp(line, "define", 6))  /* if not #define directives */
  290.          continue;                     /* set this line */
  291.       if (line [strlen(line) - 1] != '\\')      /* If #define line */
  292.          continue;                              /* ends with "\"   */
  293.       else
  294.          while (TRUE) {    /* Keep eating lines which also end with "\" */
  295.                            /* Store until newline or EOF */
  296.             if ( (c = get_ppdir_line(fp_source, line)) == EOF)
  297.                return EOF;
  298.                      /* Done with this #define directive if this */
  299.                      /* line is not also a continuation line */
  300.             if ( line [strlen(line) - 1] != '\\')
  301.                break;
  302.          }  /* end while */
  303.    }  /* end while */
  304. }  /* end flt_ppdir() */
  305.  
  306. /* Utility routine used by flt_ppdir() -
  307. *  read the character stream using flt_quotes, storing characters
  308. *  in the parameter "line" until EOF or '\n' is encountered.
  309. *  Return EOF or '\n' accordingly.
  310. */
  311.  
  312. int get_ppdir_line(fp_source, line)
  313. FILE *fp_source;
  314. char *line;
  315. {
  316.  
  317.    int i, c;
  318.  
  319.    for (i = 0; i < MAXLINE && (c = flt_quotes(fp_source)) != '\n'
  320.                                     && c != EOF; i++)
  321.       line[i] = c;
  322.    line[i] = 0;            /* terminate string */
  323.    if (c == EOF)
  324.       return EOF;
  325.    return '\n';
  326. }
  327.  
  328. /* Using the stream returned by flt_cmt() as input,
  329.  * return a character stream in which any quoted character
  330.  * or quoted string has been collapsed to the single special value QUOTES
  331.  * to avoid considering special characters like '{', '}', '(', or ')'
  332.  * which may occur within quotes.
  333.  */
  334.  
  335. int flt_quotes(fp_source)
  336. FILE *fp_source;
  337. {
  338.  
  339.    int c1, c2;
  340.  
  341.    if ( (c1 = flt_cmt(fp_source)) != '\'' && c1 != '"')
  342.       return c1;  /* pass char through if not single or double quote */
  343.    while (TRUE)
  344.       switch (c2 = flt_cmt(fp_source)) {
  345.          case '\\':        /* beginning of an escape sequence */
  346.             flt_cmt(fp_source);  /* so eat next char */
  347.             break;
  348.          case EOF:
  349.             return EOF;
  350.          default:
  351.             if (c2 == c1)  /* found end of quoted char or string */
  352.                return QUOTES;
  353.       }  /* end switch */
  354. }  /* end flt_quotes() */
  355.  
  356. /* Returns character stream, eating comments.
  357.  * Returns EOF if end of file.
  358.  * Nested comments are allowed
  359.  */
  360.  
  361. int flt_cmt(fp_source)
  362. FILE *fp_source;
  363. {
  364.  
  365.    /* values for state */
  366.    #define STABLE 0        /* not in process of changing the comment */
  367.                            /* level: i.e., not in the middle of a */
  368.                            /* slash-star or star-slash combination */
  369.    #define IN_CMT_FS 1     /* got '/', looking for '*'  */
  370.    #define OUT_CMT_STAR 2  /* got '*', looking for '/'  */
  371.  
  372.    int c, state = STABLE, cmt_level = 0;
  373.  
  374.    while (TRUE) {
  375.       c = fgetc(fp_source);
  376.       if (c == EOF)
  377.          return EOF;
  378.       switch (state) {
  379.          case STABLE:
  380.             if (c == '*')
  381.                state = OUT_CMT_STAR;
  382.             else if (c == '/')
  383.                state = IN_CMT_FS;
  384.             break;
  385.  
  386.          case IN_CMT_FS:
  387.             if (c == '*') {
  388.                state = STABLE;
  389.                cmt_level++;         /* descend one comment level */
  390.                continue;
  391.             }
  392.             else if ( !cmt_level) {    /* If '/' not followed by '*'  */
  393.                ungetc (c, fp_source);  /* push back this char */
  394.                return '/';             /* and return the '/'    */
  395.             }
  396.             else if (c != '/')         /* stay in state IN_CMT_FS */
  397.                state = STABLE;      /* if next char is '/' as well */
  398.             break;
  399.  
  400.          case OUT_CMT_STAR:
  401.             if (c == '/') {
  402.                cmt_level--;         /* ascend one comment level */
  403.                state = STABLE;
  404.                continue;
  405.             }
  406.             else if ( !cmt_level) {    /* If '*' not followed by '/'  */
  407.                ungetc (c, fp_source);  /* push back this char */
  408.                return '*';             /* and return the '*'    */
  409.             }
  410.             else if (c != '*')         /* stay in state IN_CMT_FS */
  411.                state = STABLE;      /* if next char is '*' as well */
  412.             break;
  413.       }  /* end switch */
  414.       if (state == STABLE && !cmt_level)        /* if outside any comment */
  415.          return c;                              /* return character */
  416.    }  /* end while */
  417. }  /* end flt_cmt() */
  418.  
  419.